home *** CD-ROM | disk | FTP | other *** search
- RCS_ID_C="$Id: sana2arp.c,v 3.1 1994/02/03 04:06:52 ppessi Exp $";
- /*
- * Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>,
- * Helsinki University of Technology, Finland.
- * All rights reserved.
- *
- * sana2arp.c - ARP for Sana-II Interfaces
- *
- * Last modified: Thu Feb 3 03:06:35 1994 ppessi
- *
- * HISTORY
- * $Log: sana2arp.c,v $
- * Revision 3.1 1994/02/03 04:06:52 ppessi
- * Removed OSIOCGARP (COMPAT_43); cleaned up history
- *
- * Revision 1.16 1994/01/23 21:58:01 jraja
- * Fixed one void return for SAS/C 6.51.
- *
- * Revision 1.15 1993/10/29 02:00:50 ppessi
- * Fixed ARP table entry allocation policy.
- */
-
- /*
- * Address Resolution Protocol.
- * TODO:
- * add "inuse/lock" bit (or ref. count) along with valid bit
- */
-
- #include <conf.h>
-
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/malloc.h>
- #include <sys/mbuf.h>
- #include <sys/socket.h>
- #include <sys/time.h>
- #include <sys/kernel.h>
- #include <sys/errno.h>
- #include <sys/ioctl.h>
- #include <sys/syslog.h>
- #include <sys/synch.h>
-
- #include <net/if.h>
- #include <net/if_types.h>
- #include <netinet/in.h>
- #include <netinet/in_systm.h>
- #include <netinet/in_var.h>
- #include <netinet/ip.h>
-
- #include <net/if_sana.h>
- #include <net/sana2arp.h>
-
- #include <net/if_loop_protos.h>
-
- /*
- * Internet to hardware address resolution table entry
- */
- struct arptab {
- struct arptab *at_succ; /* doubly linked list */
- struct arptab *at_pred;
- struct in_addr at_iaddr; /* internet address */
- u_char at_hwaddr[MAXADDRSANA]; /* hardware address */
- u_char at_timer; /* minutes since last reference */
- u_char at_flags; /* flags */
- struct mbuf *at_hold; /* last packet until resolved/timeout */
- };
-
- /*
- * Global constant for ARP entry allocation
- */
- unsigned long arpentries = ARPENTRIES;
-
- /*
- * General per interface hash table
- */
- struct arptable {
- struct SignalSemaphore atb_lock;
- struct arptab *atb_free;
- struct MinList atb_entries[ARPTAB_HSIZE];
- };
-
- #define ARPTAB_LOCK(atb) (ObtainSemaphore(&atb->atb_lock))
- #define ARPTAB_UNLOCK(atb) (ReleaseSemaphore(&atb->atb_lock))
- #define ARPTAB_HASH(a) ((u_long)(a) % ARPTAB_HSIZE)
-
- extern struct ifnet loif;
-
- int useloopback = 0; /* use loopback interface for local traffic */
-
- static void arpwhohas(register struct sana_softc *ssc, struct in_addr * addr);
- static void in_arpinput(register struct sana_softc *ssc, struct mbuf *m);
- static char *sana_sprintf(register u_char *ap, int len);
-
- /*
- * Initialization routine. Allocate ARP entries.
- * MUST BE CALLED AT SPLIMP.
- */
- void
- alloc_arptable(struct sana_softc* ssc, int to_allocate)
- {
- struct arptab *at;
- struct arptable *atab;
- int i;
-
- if (ssc->ss_arp.table)
- return /* (void)ssc->ss_arp.table */;
-
- #if 0
- if (to_allocate < arpentries)
- #endif
- to_allocate = arpentries;
-
- atab = bsd_malloc(sizeof(*atab), M_ARPENT, M_WAITOK);
- at = bsd_malloc(sizeof(*at) * to_allocate, M_ARPENT, M_WAITOK);
-
- if (atab && at) {
- InitSemaphore(&atab->atb_lock);
- for (i = 0; i < ARPTAB_HSIZE; i++)
- NewList((struct List *)(atab->atb_entries + i));
-
- aligned_bzero(at, sizeof(*at) * to_allocate);
-
- at[0].at_succ = NULL;
- for (i = 1; i < to_allocate; i++) {
- at[i].at_succ = &at[i - 1];
- }
- atab->atb_free = &at[to_allocate - 1];
- } else {
- if (atab) bsd_free(atab, M_ARPENT);
- if (at) bsd_free(at, M_ARPENT);
- log(LOG_ERR, "Could not allocate ARP table for %s\n", ssc->ss_name);
- }
-
- ssc->ss_arp.table = atab;
- }
-
- /*
- * Notification function for arp entries
- */
- LONG
- arpentries_notify(void *dummy, LONG value)
- {
- return (ULONG)value > ARPENTRIES_MIN;
- }
-
- /*
- * Free an arptab entry. ARP TABLE MUST BE LOCKED
- */
- static void
- arptfree(register struct arptable *atb, register struct arptab *at)
- {
- if (at->at_hold)
- m_freem(at->at_hold);
-
- Remove((struct Node *)at);
-
- if (at->at_flags & ATF_PERM) {
- bsd_free(at, M_ARPENT);
- } else {
- at->at_hold = NULL;
- at->at_timer = at->at_flags = 0;
- at->at_iaddr.s_addr = 0;
- at->at_succ = atb->atb_free;
- atb->atb_free = at;
- }
- }
-
- /*
- * Enter a new address in arptab. ARP TABLE MUST BE LOCKED
- */
- static struct arptab *
- arptnew(u_long addr, struct arptable *atb, int permanent)
- {
- struct arptab *at = NULL;
-
- if (permanent) {
- at = bsd_malloc(sizeof(*at), M_ARPENT, M_WAITOK);
- bzero((caddr_t)at, sizeof(*at));
- } else {
- at = atb->atb_free;
- if (at) {
- atb->atb_free = at->at_succ;
- } else {
- /*
- * The the oldest entry is pushed out from the
- * interface table if there is no free entry.
- * This should always succeed since all
- * entries can not be permanent
- */
- struct arptab *oldest = NULL;
- int i;
-
- for (i = 0; i < ARPTAB_HSIZE; i++) {
- for (at = (struct arptab *)atb->atb_entries[i].mlh_Head;
- at->at_succ;
- at = at->at_succ) {
- if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
- continue;
- if (!oldest || oldest->at_timer < at->at_timer)
- oldest = at;
- }
- }
- if (oldest) {
- Remove((struct Node *)oldest);
- at = oldest;
- } else {
- at = NULL;
- }
- }
- }
- if (at) {
- at->at_iaddr.s_addr = addr;
- at->at_flags = ATF_INUSE;
- AddHead((struct List *)(&atb->atb_entries[ARPTAB_HASH(addr)]),
- (struct Node *)at);
- }
- return (at);
- }
-
- /*
- * Locate an IP address in the ARP table
- * Assume looker have locked the table
- */
- static struct arptab*
- arptab_look(struct arptable *table, u_long addr)
- {
- register struct arptab *at = (struct arptab *)
- table->atb_entries[ARPTAB_HASH(addr)].mlh_Head;
-
- for(;at->at_succ; at = at->at_succ)
- if (at->at_iaddr.s_addr == addr)
- return at;
-
- return NULL;
- }
-
- /*
- * Timeout routine. Age arp_tab entries once a minute.
- */
- void
- arptimer()
- {
- struct sana_softc *ssc;
- register struct arptable *atab;
- register struct arptab *at, *oldest;
- register i;
-
- for (ssc = ssq; ssc; ssc = ssc->ss_next) {
- if (!(atab = ssc->ss_arp.table))
- continue;
- /* Lock the table */
- ARPTAB_LOCK(atab);
- oldest = NULL;
- for (i = 0; i < ARPTAB_HSIZE; i++) {
- for (at = (struct arptab *)atab->atb_entries[i].mlh_Head;
- at->at_succ;
- at = at->at_succ) {
- if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
- continue;
- if (++at->at_timer < ((at->at_flags & ATF_COM) ?
- ARPT_KILLC : ARPT_KILLI))
- continue;
- /* timer has expired, clear entry */
- arptfree(atab, at);
- }
- }
- ARPTAB_UNLOCK(atab);
- }
- }
-
- /*
- * Broadcast an ARP packet, asking who has addr on interface ssc.
- */
- static void
- arpwhohas(register struct sana_softc *ssc, struct in_addr *addr)
- {
- register struct mbuf *m;
- register struct s2_arppkt *s2a;
- struct sockaddr_sana2 ss2;
-
- if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
- return;
- m->m_len = sizeof(*s2a);
- m->m_pkthdr.len = sizeof(*s2a);
- MH_ALIGN(m, sizeof(*s2a));
- s2a = mtod(m, struct s2_arppkt *);
- aligned_bzero_const((caddr_t)s2a, sizeof (*s2a));
- m->m_flags |= M_BCAST;
-
- /* fill in header depending of the interface */
- s2a->arp_hrd = ssc->ss_arp.hrd;
- s2a->arp_pro = htons(ssc->ss_ip.type);
- s2a->arp_pln = sizeof(struct in_addr); /* protocol address length */
- s2a->arp_hln = ssc->ss_if.if_addrlen; /* hardware address length */
- s2a->arp_op = htons(ARPOP_REQUEST);
-
- /* Copy source hardware address */
- bcopy((caddr_t)ssc->ss_hwaddr,
- (caddr_t)&s2a->arpdata,
- s2a->arp_hln);
- /* Copy source protocol address */
- bcopy((caddr_t)&ssc->ss_ipaddr,
- (caddr_t)&s2a->arpdata + s2a->arp_hln,
- s2a->arp_pln);
- /* Zero target hardware address */
- bzero((caddr_t)&s2a->arpdata + s2a->arp_hln + s2a->arp_pln,
- s2a->arp_hln);
- /* Copy target protocol address */
- bcopy((caddr_t)addr,
- (caddr_t)&s2a->arpdata + 2 * s2a->arp_hln + s2a->arp_pln,
- s2a->arp_pln);
-
- /* Send an ARP packet */
- ss2.ss2_len = sizeof(ss2);
- ss2.ss2_family = AF_UNSPEC;
- ss2.ss2_type = ssc->ss_arp.type;
- (*ssc->ss_if.if_output)(&ssc->ss_if, m, (struct sockaddr *)&ss2,
- (struct rtentry *)0);
- }
-
- /*
- * Resolve an IP address into an SANA-II address. If success,
- * desten is filled in. If there is no entry in arptab,
- * set one up and broadcast a request for the IP address.
- * Hold onto this mbuf and resend it once the address
- * is finally resolved. A return value of 1 indicates
- * that desten has been filled in and the packet should be sent
- * normally; a 0 return indicates that the packet has been
- * taken over here, either now or for later transmission.
- *
- * We do some (conservative) locking here at splimp, since
- * arptab is also altered from sana poll routine
- */
- int
- arpresolve(register struct sana_softc *ssc,
- struct mbuf *m,
- register struct in_addr *destip,
- register u_char *desten,
- int *error)
- {
- register struct arptab *at;
- register struct arptable *atb;
- struct sockaddr_in sin;
- register struct in_ifaddr *ia;
- u_long lna;
-
- if (m->m_flags & M_BCAST) { /* broadcast */
- return 1;
- }
- lna = in_lnaof(*destip);
- /* if for us, use software loopback driver if up */
- for (ia = in_ifaddr; ia; ia = ia->ia_next)
- if ((ia->ia_ifp == &ssc->ss_if) &&
- (destip->s_addr == ia->ia_addr.sin_addr.s_addr)) {
- /*
- * This test used to be
- * if (loif.if_flags & IFF_UP)
- * It allowed local traffic to be forced
- * through the hardware by configuring the loopback down.
- * However, it causes problems during network configuration
- * for boards that can't receive packets they send.
- * It is now necessary to clear "useloopback"
- * to force traffic out to the hardware.
- */
- if (useloopback) {
- sin.sin_family = AF_INET;
- sin.sin_addr = *destip;
- (void) looutput(&loif, m, (struct sockaddr *)&sin, 0);
- /*
- * The packet has already been sent and freed.
- */
- return (0);
- } else {
- bcopy((caddr_t)ssc->ss_hwaddr, (caddr_t)desten, ssc->ss_if.if_addrlen);
- return (1);
- }
- }
-
- if (ssc->ss_if.if_flags & IFF_NOARP) {
- /* No arp */
- log(LOG_ERR,
- "arpresolve: can't resolve address for if %s/%ld\n",
- ssc->ss_if.if_name, ssc->ss_if.if_unit);
- *error = ENETUNREACH;
- m_freem(m);
- return (0);
- }
-
- /* Try to locate ARP table */
- if (!(atb = ssc->ss_arp.table)) {
- alloc_arptable(ssc, 0);
- if (!(atb = ssc->ss_arp.table)) {
- log(LOG_ERR, "arpresolve: memory exhausted");
- *error = ENOBUFS;
- m_free(m);
- return 0;
- }
- }
-
- ARPTAB_LOCK(atb);
- at = arptab_look(atb, destip->s_addr);
- if (at == 0) { /* not found */
- at = arptnew(destip->s_addr, atb, FALSE);
- if (at) {
- at->at_hold = m;
- arpwhohas(ssc, destip);
- } else {
- log(LOG_ERR, "arpresolve: no free entry");
- *error = ENETUNREACH;
- m_free(m);
- }
- ARPTAB_UNLOCK(atb);
- return 0;
- }
-
- at->at_timer = 0; /* restart the timer */
- if (at->at_flags & ATF_COM) { /* entry IS complete */
- bcopy((caddr_t)at->at_hwaddr, (caddr_t)desten, ssc->ss_if.if_addrlen);
- ARPTAB_UNLOCK(atb);
- return 1;
- }
- /*
- * There is an arptab entry, but no address response yet.
- * Replace the held mbuf with this latest one.
- */
- if (at->at_hold)
- m_freem(at->at_hold);
- at->at_hold = m;
- arpwhohas(ssc, destip); /* ask again */
- ARPTAB_UNLOCK(atb);
- return 0;
- }
-
- /*
- * Called from the sana poll routine
- * when ARP type packet is received.
- * Common length and type checks are done here,
- * then the protocol-specific routine is called.
- * In addition, a sanity check is performed on the sender
- * protocol address, to catch impersonators.
- */
- void
- arpinput(struct sana_softc *ssc,
- struct mbuf *m,
- caddr_t srcaddr)
- {
- register struct arphdr *ar;
- int proto;
-
- if (ssc->ss_if.if_flags & IFF_NOARP)
- goto out;
- if (m->m_len < sizeof(struct arphdr))
- goto out;
- ar = mtod(m, struct arphdr *);
- if (ntohs(ar->ar_hrd) != ssc->ss_arp.hrd)
- goto out;
- if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
- goto out;
- if (ar->ar_hln != ssc->ss_if.if_addrlen)
- goto out;
-
- #ifdef paranoid_arp_mode
- /* Sanity check */
- if (bcmp(srcaddr, (UBYTE*)ar + sizeof(*ar), ar->ar_hln)) {
- log(LOG_ERR, "An ARP packet sent as %s",
- sana_sprintf(srcaddr, ar->ar_hln));
- log(LOG_ERR, " from address: %s!!\n",
- sana_sprintf((UBYTE*)ar + sizeof(*ar), ar->ar_hln));
- goto out;
- }
- #endif
-
- proto = ntohs(ar->ar_pro);
-
- if (proto == ssc->ss_ip.type) {
- in_arpinput(ssc, m);
- return;
- }
-
- out:
- m_freem(m);
- }
-
- /*
- * ARP for Internet protocols on SANA-II interfaces.
- * Algorithm is that given in RFC 826.
- */
- static void
- in_arpinput(register struct sana_softc *ssc,
- struct mbuf *m)
- {
- register struct s2_arppkt *s2a;
- struct sockaddr_in sin;
- struct in_addr isaddr, itaddr, myaddr;
- int op, completed = 0;
- caddr_t sha, spa, tha, tpa;
- size_t len = ssc->ss_if.if_addrlen;
-
- s2a = mtod(m, struct s2_arppkt *);
- op = ntohs(s2a->arp_op);
-
- if (s2a->arp_pln != sizeof(struct in_addr))
- goto out;
-
- sha = (caddr_t)&(s2a->arpdata); /* other members must be calculated */
- bcopy(spa = sha + len, (caddr_t)&isaddr, sizeof (isaddr));
- tha = spa + sizeof(struct in_addr);
- bcopy(tpa = tha + len, (caddr_t)&itaddr, sizeof (itaddr));
-
-
- {
- register struct in_ifaddr *ia;
- struct in_ifaddr *maybe_ia = 0;
-
- /* Check for our own ARP packets */
- for (ia = in_ifaddr; ia; ia = ia->ia_next)
- if (ia->ia_ifp == &ssc->ss_if) {
- maybe_ia = ia;
- if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
- (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr))
- break;
- }
- if (maybe_ia == 0)
- goto out;
- myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
- if (!bcmp(sha, (caddr_t)ssc->ss_hwaddr, len))
- goto out; /* it's from me, ignore it. */
- }
- #ifndef AMITCP
- if (!bcmp(sha, (caddr_t)etherbroadcastaddr, ac->ac_if.if_addrlen)) {
- log(LOG_ERR,
- "arp: ether address is broadcast for IP address %lx!\n",
- ntohl(isaddr.s_addr));
- goto out;
- }
- #endif
-
- /* Check for duplicate IP addresses */
- if (isaddr.s_addr == myaddr.s_addr) {
- log(LOG_ERR,
- "duplicate IP address %lx!! sent from hardware address: %s\n",
- ntohl(isaddr.s_addr),
- sana_sprintf(sha, len));
- itaddr = myaddr;
- if (op == ARPOP_REQUEST)
- goto reply;
- goto out;
- }
-
- {
- struct arptable *atb;
- register struct arptab *at = NULL; /* same as "merge" flag */
-
- /* Try to locate ARP table */
- if (!(atb = ssc->ss_arp.table)) {
- goto reply;
- }
-
- ARPTAB_LOCK(atb);
- at = arptab_look(atb, isaddr.s_addr);
-
- if (at) {
- bcopy(sha, (caddr_t)at->at_hwaddr, len);
- if ((at->at_flags & ATF_COM) == 0)
- completed = 1;
- at->at_flags |= ATF_COM;
- if (at->at_hold) {
- sin.sin_family = AF_INET;
- sin.sin_addr = isaddr;
- (*ssc->ss_if.if_output)(&ssc->ss_if, at->at_hold,
- (struct sockaddr *)&sin, (struct rtentry *)0);
- at->at_hold = 0;
- }
- }
- if (at == 0 && itaddr.s_addr == myaddr.s_addr) {
- /* ensure we have a table entry */
- if (at = arptnew(isaddr.s_addr, atb, FALSE)) {
- bcopy(sha, (caddr_t)at->at_hwaddr, len);
- completed = 1;
- at->at_flags |= ATF_COM;
- }
- }
- ARPTAB_UNLOCK(atb);
- }
-
- reply:
- /*
- * Reply if this is an IP request
- */
- if (op != ARPOP_REQUEST)
- goto out;
-
- if (itaddr.s_addr == myaddr.s_addr) {
- /* I am the target */
- bcopy(sha, tha, len);
- bcopy((caddr_t)ssc->ss_hwaddr, sha, len);
- } else {
- /* Answer if we have a public entry */
- register struct arptab *at;
-
- /* Try to locate ARP table */
- if (!ssc->ss_arp.table)
- goto out;
-
- ARPTAB_LOCK(ssc->ss_arp.table);
- at = arptab_look(ssc->ss_arp.table, itaddr.s_addr);
- if (at && (at->at_flags & ATF_PUBL)) {
- bcopy(sha, tha, len);
- bcopy(at->at_hwaddr, sha, len);
- } else {
- at = NULL;
- }
- ARPTAB_UNLOCK(ssc->ss_arp.table);
- if (!at)
- goto out;
- }
- {
- struct sockaddr_sana2 ss2;
- bcopy(spa, tpa, sizeof(struct in_addr));
- bcopy((caddr_t)&itaddr, spa, sizeof(struct in_addr));
- s2a->arp_op = htons(ARPOP_REPLY);
-
- ss2.ss2_len = sizeof(ss2);
- ss2.ss2_family = AF_UNSPEC;
- ss2.ss2_type = ssc->ss_arp.type;
- bcopy(tha, ss2.ss2_host, len);
-
- m->m_flags &= ~(M_BCAST|M_MCAST);
-
- (*ssc->ss_if.if_output)(&ssc->ss_if, m, (struct sockaddr *)&ss2,
- (struct rtentry *)0);
- return;
- }
- out:
- m_freem(m);
- return;
- }
-
- int
- arpioctl(cmd, data)
- int cmd;
- caddr_t data;
- {
- register struct arpreq *ar = (struct arpreq *)data;
- register struct arptab *at;
- register struct sockaddr_in *sin;
- struct arptable *atb;
- struct ifaddr *ifa;
- struct sana_softc *ssc;
- spl_t s;
-
- sin = (struct sockaddr_in *)&ar->arp_pa;
- sin->sin_len = sizeof(ar->arp_pa);
-
- if (ar->arp_pa.sa_family != AF_INET ||
- ar->arp_ha.sa_family != AF_UNSPEC)
- return (EAFNOSUPPORT);
-
- s = splimp();
- if ((ifa = ifa_ifwithnet(&ar->arp_pa)) == NULL) {
- splx(s);
- return (ENETUNREACH);
- }
-
- ssc = (struct sana_softc *)ifa->ifa_ifp;
- splx(s);
-
- if (ssc->ss_if.if_type != IFT_SANA || !(atb = ssc->ss_arp.table)) {
- return (EAFNOSUPPORT);
- }
-
- ARPTAB_LOCK(atb);
-
- if (cmd != SIOCGARPT) {
- at = arptab_look(atb, sin->sin_addr.s_addr);
- if (at == NULL && cmd != SIOCSARP) {
- ARPTAB_UNLOCK(atb);
- return (ENXIO);
- }
- }
-
- switch (cmd) {
-
- case SIOCSARP: /* set entry */
- if (ar->arp_ha.sa_len > sizeof(at->at_hwaddr) + 2 ||
- ar->arp_ha.sa_len != ssc->ss_if.if_addrlen + 2) {
- ARPTAB_UNLOCK(atb);
- return (EINVAL);
- }
- /*
- * Free if new entry should be allocated in a different way
- */
- if (at != NULL && (at->at_flags ^ ar->arp_flags) & ATF_PERM) {
- arptfree(atb, at);
- at = NULL;
- }
- if (at == NULL) {
- at = arptnew(sin->sin_addr.s_addr, atb, ar->arp_flags & ATF_PERM);
- if (at == NULL) {
- ARPTAB_UNLOCK(atb);
- return (EADDRNOTAVAIL);
- }
- }
-
- bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_hwaddr,
- ar->arp_ha.sa_len - 2);
- at->at_flags = ATF_COM | ATF_INUSE |
- (ar->arp_flags & (ATF_PERM|ATF_PUBL));
- at->at_timer = 0;
- break;
-
- case SIOCDARP: /* delete entry */
- arptfree(atb, at);
- break;
-
- case SIOCGARP: /* get entry */
- bcopy((caddr_t)at->at_hwaddr, (caddr_t)ar->arp_ha.sa_data,
- ar->arp_ha.sa_len = ssc->ss_if.if_addrlen + 2);
- ar->arp_flags = at->at_flags;
- break;
-
- case SIOCGARPT: /* get table */
- {
- int i, n; long siz;
- register struct arptabreq *atr = (struct arptabreq *)data;
- ar = atr->atr_table;
- siz = ar ? atr->atr_size : 0;
-
- for (n = i = 0; i < ARPTAB_HSIZE; i++) {
- for (at = (struct arptab *)atb->atb_entries[i].mlh_Head;
- at->at_succ;
- at = at->at_succ) {
- n++;
- if (siz > 0) {
- struct sockaddr_in *sin = (struct sockaddr_in *)&ar->arp_pa;
- sin->sin_len = sizeof(*sin);
- sin->sin_family = AF_INET;
- sin->sin_addr = at->at_iaddr;
- bcopy((caddr_t)at->at_hwaddr, (caddr_t)ar->arp_ha.sa_data,
- ar->arp_ha.sa_len = ssc->ss_if.if_addrlen + 2);
- ar->arp_flags = at->at_flags;
- siz--;
- ar++;
- }
- }
- }
- atr->atr_size -= siz;
- atr->atr_inuse = n;
- }
- }
-
- ARPTAB_UNLOCK(atb);
- return 0;
- }
-
- static const char *digits = "0123456789ABCDEF";
- /*
- * Print Hardware Address
- */
- static char *sana_sprintf(register u_char *ap, int len)
- {
- register i;
- static char addrbuf[17*3];
- register unsigned char *cp = addrbuf;
-
- for (i = 0; i < len; ) {
- *cp++ = digits[*ap >> 4];
- *cp++ = digits[*ap++ & 0xf];
- i++;
- if (i < len)
- *cp++ = ':';
- }
- *cp = 0;
- return (addrbuf);
- }
-